package spring.mvc.controller;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.caucho.HessianProxyFactoryBean;
import org.springframework.remoting.caucho.HessianServiceExporter;
import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
import spring.mvc.MyWebAppInitializer;
import spring.mvc.service.HelloService;

/**
 * HttpInvokerServiceExporter
 * HttpInvoker 是过去常用的 Java 同构系统之间方法调用实现方案。它通过 HTTP 通信即可实现两个 Java 系统之间的远程方法调用，使得系统之间的通信如同调用本地方法一般。
 * HttpInvoker 和 RMI 同样使用 JDK 自带的序列化方式，但是 HttpInvoker 采用 HTTP 方式通信，这更容易配合防火墙、网闸的工作。
 * RMI：使用 JRMP 协议(基于 TCP/IP)，不允许穿透防火墙，使用 JAVA 系列化方式，使用于任何 JAVA 应用之间相互调用
 * Hessian：使用 HTTP 协议，允许穿透防火墙，使用自己的系列化方式，支持 JAVA、C++、.Net 等跨语言使用
 * Spring HTTP Invoker: 使用 HTTP 协议，允许穿透防火墙，使用 JAVA 系列化方式，但仅限于 Spring 应用之间使用，即调用者与被调用者都必须是使用 Spring 框架的应用。
 */
@Configuration
public class My_03_HttpInvokerServiceExporter {
    /**
     * @see MyWebAppInitializer#registerDispatcherServlet(javax.servlet.ServletContext)
     * 服务端：把 HelloService 暴露出去，服务端对接口必须有具体的实现
     * 因为服务端需要提供 HTTP 请求服务，而且是基于 Servlet 的，所以服务端需要跑在如 Tomcat 这样的 Servlet Web 容器上
     * @see HessianServiceExporter
     */
    @Bean
    // @Bean("/helloService") // 注意这里的 BeanName 使用 / 路径的形式(推荐使用这种方式，简单明了)
    public HttpInvokerServiceExporter helloServiceExporter(HelloService helloServiceImpl) {
        HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter();
        exporter.setServiceInterface(HelloService.class); // 必须设置一个接口
        exporter.setService(helloServiceImpl); // 真正的实现类，这个对服务端来说是必须的
        return exporter;
    }

    /**
     * 客户端书写：写一个和服务端一样的接口（不需要实现类）配置上
     *
     * @see HessianProxyFactoryBean
     */
    @Bean("helloServiceFactoryBean")
    public HttpInvokerProxyFactoryBean helloServiceFactoryBean() {
        HttpInvokerProxyFactoryBean factoryBean = new HttpInvokerProxyFactoryBean();
        factoryBean.setServiceInterface(HelloService.class);
        factoryBean.setServiceUrl("http://127.0.0.1:80/rmi_helloService");
        return factoryBean;
    }
}
